﻿using System;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using Microsoft.Win32;

namespace Tsanie.ShellExt.Definitions
{
    /// <summary>
    /// Thumbnail Handler 的基类
    /// </summary>
    public abstract class ThumbnailHandlerBase : PersistFileBase, IExtractImage, IExtractImage2
    {
        #region - 私有字段 -

        Size m_Size;
        int m_ColorDepth;

        #endregion

        #region - 构造 -

        protected ThumbnailHandlerBase() { }

        #endregion

        #region - 公共属性 -

        /// <summary>
        /// 获取推荐的颜色深度
        /// </summary>
        public int RecomendedColorDepth { get { return m_ColorDepth; } }
        /// <summary>
        /// 获取推荐的缩略图大小
        /// </summary>
        public Size RecomendedSize { get { return m_Size; } }

        #endregion

        #region - 子类重写属性 -

        /// <summary>
        /// 返回缩略图
        /// </summary>
        protected abstract System.Drawing.Bitmap GetImage { get; }
        /// <summary>
        /// 图像最后修改时间
        /// </summary>
        protected virtual DateTime DateStamp { get { return DateTime.Now; } }
        protected virtual string GetThumbnailLocation { get { return this.Filename; } }
        /// <summary>
        /// 如果缩略图被异步生成, 这个表示缩略图生成线程的优先级
        /// </summary>
        protected virtual int GetPriority { get { return 0; } }
        protected virtual ThumbnailFlags GetFlag { get { return ThumbnailFlags.Cache | ThumbnailFlags.Async; } }

        #endregion

        #region - IExtractImage 成员 -

        IntPtr Extract() { return this.GetImage.GetHbitmap(); }
        IntPtr IExtractImage.Extract() { return Extract(); }
        IntPtr IExtractImage2.Extract() { return Extract(); }

        void GetLocation(StringBuilder pszPathBuffer, int cch, out int pdwPriority, ref SIZE prgSize, int dwRecClrDepth, ref ThumbnailFlags pdwFlags)
        {
            m_Size.Width = prgSize.cx;
            m_Size.Height = prgSize.cy;
            m_ColorDepth = dwRecClrDepth;

            pdwFlags = this.GetFlag;
            pdwPriority = this.GetPriority;

            pszPathBuffer = new StringBuilder(this.GetThumbnailLocation);
        }
        void IExtractImage.GetLocation(StringBuilder pszPathBuffer, int cch, out int pdwPriority, ref SIZE prgSize, int dwRecClrDepth, ref ThumbnailFlags pdwFlags)
        {
            GetLocation(pszPathBuffer, cch, out pdwPriority, ref prgSize, dwRecClrDepth, ref pdwFlags);
        }
        void IExtractImage2.GetLocation(StringBuilder pszPathBuffer, int cch, out int pdwPriority, ref SIZE prgSize, int dwRecClrDepth, ref ThumbnailFlags pdwFlags)
        {
            GetLocation(pszPathBuffer, cch, out pdwPriority, ref prgSize, dwRecClrDepth, ref pdwFlags);
        }

        long IExtractImage2.GetDateStamp() { return DateStamp.ToFileTime(); }

        #endregion

        #region - COM 组件注册 -

        [System.Runtime.InteropServices.ComRegisterFunction]
        static void ComReg(Type t)
        {
            Common.RegisterExtension(t, "{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}");
            bool changed = false;
            foreach (ThumbnailBaseProvider provider in Extension.Where(Common.Providers, p => p.Type == ProviderType.Thumbnail))
            {
                foreach (string ext in provider.Exts)
                {
                    changed |= Common.RegisterKey(ext, "{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}", ProviderType.Thumbnail);
                }
            }
            // 注册了键值就刷新explorer
            if (changed)
            {
                Common.SHChangeNotify(Common.SHCNE_ASSOCCHANGED, 0, IntPtr.Zero, IntPtr.Zero);
            }
        }

        [System.Runtime.InteropServices.ComUnregisterFunction]
        static void ComUnreg(Type t)
        {
            foreach (ThumbnailBaseProvider provider in Extension.Where(Common.Providers, p => p.Type == ProviderType.Thumbnail))
            {
                foreach (string ext in provider.Exts)
                {
                    Common.UnregisterKey(ext, "{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}", ProviderType.Thumbnail);
                }
            }
            Common.UnregisterExtension(t, "{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}");
        }

        #endregion
    }
}
